/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pnt.server;

import java.io.IOException;
import java.net.*;
import java.util.logging.Logger;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.Enumeration;

/**
 *
 * @author andrew
 */
public class TCPConnectionListener extends ConnectionListener {

    private static Logger logger = Logger.getLogger("pnt.server"); 
    
    ServerSocket primarySocket;
    ConnectionManager conmgr;
    boolean running = false;
    
    static InetAddress primary = null;
    static InetAddress helper = null;
    
    public TCPConnectionListener(int port, ConnectionManager conmgr, boolean isHelper){
        // TODO: fork into lightweight vs full implementations for helper nodes.
        // NOTE: helper nodes don't use ssl
        try{
            if (primary == null || helper == null)
                initInterfaceAddresses();
            
            if(isHelper){
                primarySocket = new ServerSocket(port, 0, helper);
                logger.info("Helper server started on " + primary.getHostAddress() + " port " + port);
            }else{
                primarySocket = new ServerSocket(port, 0, primary);
                logger.info("Primary server started on " + primary.getHostAddress() + " port " + port);
            }
            this.conmgr = conmgr;
        } catch (IOException ex){
            System.err.println("Error establishing TCP Socket." + ex);
        }
    }
    
    public void run() {
        running = true;
        while(running){
            try {

                Socket tcpConnection = primarySocket.accept();
                
                // A connection has been received. Send it to the connection manager.
                conmgr.addConnection(new TCPConnection(tcpConnection));
                
            } catch (IOException ex) {
                System.err.println("Unable to create TCP socket connection." + ex);
            }
        }
    }

    public boolean stop() {
        try {
            primarySocket.close();
            running = false;
            return true;
        } catch (IOException ex) {
            return false;
        }
    }

    public InetAddress getAddr(){
        return primarySocket.getInetAddress();
    }
    
    public int getPort(){
        return primarySocket.getLocalPort();
    }

    /**
     * At this stage assigns both primary and helper addresses to the IP4 address
     * assigned to either etho or en1 (in that order). If eth1 is present, the
     * helper operates on its IP4 address.
     * 
     * @throws java.net.SocketException
     */
    private static void initInterfaceAddresses() throws SocketException {
        // TODO: alter this to check from config file, if no file exists
        // then prompt user and generate one.
        NetworkInterface i1, i2;
        
        i1 = NetworkInterface.getByName("eth0");
        if (i1 == null)
            i1 = NetworkInterface.getByName("en1");
        if (i1 == null)
            i1 = NetworkInterface.getByName("en0");
        
        i2 = NetworkInterface.getByName("eth1");
        if (i2 == null) i2 = i1;
        if (i1 == null) i1 = i2;
        
        if (i1 == null){
            
            logger.severe("Unable to find interface to retrieve IP address");
            throw new Error("Unable to find valid interface");
            
        }
        
        Enumeration <InetAddress> addrs1 = i1.getInetAddresses();
        Enumeration <InetAddress> addrs2 = i1.getInetAddresses();
        
        for(InetAddress a : Collections.list(addrs1))
            // we only want IP4 addresses
            if (a.getClass().equals(java.net.Inet4Address.class))
                primary = a;
        
        for(InetAddress a : Collections.list(addrs2))
            // we only want IP4 addresses
            if (a.getClass().equals(java.net.Inet4Address.class))
                helper = a;
    }
}
